package sk.upjs.ics.fca;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;

/**
 * Trieda, ktora sa stara o generovanie fuzzy kontextov podla fill ratia -
 * percentualne zastupenie nenulovych hodnot v kontexte
 * 
 * @author RE56429
 * 
 */
public class Generator {

	private List<Double> truthValues = Arrays.asList(0.5, 1.0);
	private int n;
	private int m;
	private Random random;

	// percentage of nonzero entries in the context
	// 0.00 - 1.00
	private double fillRatio;

	private List<Double> sequence = new ArrayList<Double>();

	private List<List<Double>> relation = new ArrayList<List<Double>>();

	/**
	 * Konstruktor prijima ako vstupy rozmery kontextu a fill ratio
	 * 
	 * @param n
	 *            pocet objektov
	 * @param m
	 *            pocet atributov
	 * @param fillRatio
	 *            fill ratio - percentualne zastupenie nenulovych hodnot v
	 *            kontexte
	 */
	public Generator(int n, int m, double fillRatio) {
		super();
		this.random = new Random();
		this.n = n;
		this.m = m;
		this.fillRatio = fillRatio;
	}

	/**
	 * Zacne generovanie relacie
	 */
	public void generateRelation() {
		relation = new ArrayList<List<Double>>();
		generateSequence();

		int p = 0;
		for (int i = 0; i < n; i++) {
			this.relation.add(new ArrayList<Double>());
			for (int j = 0; j < m; j++) {
				this.relation.get(i).add(sequence.get(p++));
			}
		}
	}

	private void generateSequence() {
		sequence = new ArrayList<Double>();

		int numberOfElements = n * m;

		// round number of nonzero elements
		int numberOfNonZeroElements = (int) Math.floor(numberOfElements
				* this.fillRatio + 0.5f);
		int numberOfZeroElements = numberOfElements - numberOfNonZeroElements;

		// add zero elements
		for (int i = 0; i < numberOfZeroElements; i++) {
			this.sequence.add(0.0);
		}

		// add randomly chosen 0.5 or 1.0
		for (int i = 0; i < numberOfNonZeroElements; i++) {
			this.sequence.add(getRandomDouble());
		}

		// shuffle generated sequence
		Collections.shuffle(sequence);
	}

	private Double getRandomDouble() {
		int randomIndex = random.nextInt(truthValues.size());
		return truthValues.get(randomIndex);
	}

	/**
	 * Vrati vygenerovany kontext
	 * 
	 * @return kontext
	 */
	public List<List<Double>> getRelation() {
		return relation;
	}
}
